package com.taotaojs.util;

import com.taotaojs.exception.MyInnerException;
import com.taotaojs.util.number.NumberFormatUtil;
import com.taotaojs.util.reflect.ReflectUtil;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 集合工具类
 *
 * @author TaoTaojs
 * @author: TaoTaojs
 * @Date: 2020/7/2 2:23 PM
 * @Description:
 * 将集合转换为以指定分隔符分隔的字符串【toString()】
 * 将已被固定字符分隔成的字符串拆分为指定类型集合【get***()】
 * 获取集合中复杂对象某个属性并整理为集合【get***()】
 * 比较两个复杂或基本类型集合对结果返回交集【compareToArray***()】
 * 获取集合中重复的对象集合并去重【getRepeat()】
 * 判断Map与Collection对应对象是否为空【isEmpty(), isNotEmpty()】
 * 判断Map与Collection为空就新建的逻辑【isCreate***()】
 * 判断集合/数组中是否存在某个元素
 * @关联类:
 * @参考链接：
 * @History: <br/>
 * <author>        <time>                      <version>          <desc>
 * TaoTaojs        2020/7/2 2:23 PM                V1.0           支持将集合转换为以分隔符分隔的字符串，获取集合中对象某个不确定类型属性并整理为集合，比较两个复杂或基本类型集合对结果返回交集，获取集合中重复的对象集合并去重，判断Map与Collection对应对象是否为空与为空就新建的逻辑
 */

public class CollectionUtil {

    private CollectionUtil(){}

    /**
     * 将集合转换为逗号分隔的字符串
     * @param list
     * @return
     */
    public static<T> String toString(List<T> list){
        if(CollectionUtil.isEmpty(list)) {
            return "";
        }
        return StringUtil.join(list.toArray());
    }


    /**
     * 获取自定义属性并整理成集合
     * @param list
     * @param calzz
     * @param methodName
     * @param <T>
     * @param <V>
     * @return
     */
    public static<T,V> List<T> getPros(List<V> list, Class<V> calzz, String methodName){
        List<T> reList = new ArrayList<>();
        Method getMethod = ReflectUtil.getGetMethod(calzz, methodName);
        for (V v : list) {
            try {
                Object pro = getMethod.invoke(v);
                if(pro != null){
                    reList.add((T) pro);
                }
            } catch (Exception e) {
                throw new MyInnerException(e);
            }
        }
        return reList;
    }

    /**
     * 将字符串转换成Integer集合
     * @param listStr
     * @param regex
     * @return
     */
    public static List<Integer> getInteger(String listStr, String regex){
        if(StringUtil.isBlank(listStr) || StringUtil.isBlank(regex)){
            return new ArrayList<>();
        }
        return Arrays.asList(listStr.split(regex)).stream()
                .filter(str -> !str.isEmpty())
                .map(NumberFormatUtil::stringToInteger)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 将字符串转换为string集合
     * @param listStr
     * @param regex
     * @return
     */
    public static List<String> getStrs(String listStr, String regex){
        if(StringUtil.isBlank(listStr) || StringUtil.isBlank(regex)){
            return new ArrayList<>();
        }
        return Arrays.asList(listStr.split(regex)).stream()
                .filter(str -> !str.isEmpty())
                .collect(Collectors.toList());
    }

    /**
     * 将字符串转换为数字集合（双精度集合）
     * @param listStr
     * @param regex
     * @return
     */
    public static List<Double> getNumber(String listStr, String regex){
        if(StringUtil.isBlank(listStr) || StringUtil.isBlank(regex)){
            return new ArrayList<>();
        }
        return Arrays.asList(listStr.split(regex)).stream()
                .filter(str -> !str.isEmpty())
                .map(NumberFormatUtil::stringToDouble)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    public static<T> List<Integer> getIds(List<T> list, Class<T> clazz){
        return getPros(list, clazz, "id");
    }
    public static List<Integer> getIds(String listStr){
        return getInteger(listStr, ",");
    }
    public static List<Integer> getInteger(String listStr){
        return getInteger(listStr, ",");
    }
    public static<T> List<String> getStrs(List<T> list, Class<T> clazz, String methodName){
        return getPros(list, clazz, methodName);
    }
    public static List<String> getStrs(String listStr){
        return getStrs(listStr);
    }
    public static<T> List<Integer> getNumber(List<T> list, Class<T> clazz, String methodName){
        return getPros(list, clazz, methodName);
    }
    public static List<Double> getNumber(String listStr){
        return getNumber(listStr);
    }

    public static<T> void toNotEmpty(Collection<T> coll){
        Iterator<T> it = coll.iterator();
        while(it.hasNext()){
            T x = it.next();
            if(x == null){
                it.remove();
            }
        }
    }

    /**
     * 比较两个集合，找出其中的交集，并返回（找到过程中会删除原来两个集合中的数据引用） - 使用equals判断
     * @param clazz 对象类型
     * @param listDb DB - 返回一个需要删除的列表
     * @param listVO VO - 返回一个需要添加的列表
     * @param <T> 对象类型
     * @return 返回两个集合的交集 - 返回一个需要修改的列表
     */
    public static<T> List<T> compareToArray(Class<T> clazz, List<T> listDb, List<T> listVO, String keyName){
        List<T> list = new ArrayList<>();
        if(listDb == null || listVO == null) {
            return list;
        }

        toNotEmpty(listDb);
        toNotEmpty(listVO);

        Method getKeyMethod = ReflectUtil.getGetMethod(clazz, keyName);
        Method setKeyMethod = ReflectUtil.getSetMethod(clazz, keyName, getKeyMethod.getReturnType());

        Iterator<T> iterator1 = listDb.iterator();

        while(iterator1.hasNext()){
            T item1 = iterator1.next();
            Iterator<T> iterator2 = listVO.iterator();
            while(iterator2.hasNext()){
                T item2 = iterator2.next();
                if(compareToArrayReturnJudge(getKeyMethod, setKeyMethod, item1, item2)){
                    iterator1.remove();
                    iterator2.remove();
                    list.add(item2);
                    break;
                }
            }
        }

        return list;
    }
    public static<T> List<T> compareToArray(Class<T> clazz, List<T> listDb, List<T> listVO){
        return compareToArray(clazz, listDb, listVO, "id");
    }

    /**
     * 比较两个集合并获取交集方法的主要处理方法（为了降低代码复杂度，特拆开）
     * @param getKeyMethod
     * @param setKeyMethod
     * @param item1
     * @param item2
     * @param <T>
     * @return
     */
    private static<T> boolean compareToArrayReturnJudge(Method getKeyMethod, Method setKeyMethod, T item1, T item2){
        Object key1 = ReflectUtil.invokeMethod(item1, getKeyMethod);
        Object key2 = ReflectUtil.invokeMethod(item2, getKeyMethod);
        if (key1 != null && key2 != null && key1.equals(key2)) {
            //如果两个对象都有key值，且key值相同
            return true;
        } else if (key1 != null && key2 == null && item1.equals(item2)){
            //如果VO没有key值，且两个对象equals相同
            ReflectUtil.invokeMethod(item2, setKeyMethod, key1);
            return true;
        } else if (key1 == null && key2 != null && item1.equals(item2)){
            //如果DB没有key值，且两个对象equals相同
            return true;
        }
        return false;
    }

    /**
     * 对比基本类型集合的方法（直接对比equals方法）
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public static<T> List<T> compareToArrayBasic(List<T> list1, List<T> list2){
        List<T> list = new ArrayList<>();
        if(list1 == null || list2 == null) {
            return list;
        }

        Iterator<T> iterator1 = list1.iterator();
        while(iterator1.hasNext()) {
            T item1 = iterator1.next();
            Iterator<T> iterator2 = list2.iterator();
            while (iterator2.hasNext()) {
                T item2 = iterator2.next();
                if(item1.equals(item2)){
                    iterator1.remove();
                    iterator2.remove();
                    list.add(item2);
                    break;
                }
            }
        }
        return list;
    }

    /**
     * 获取一个集合中重复的对象并返回为一个集合
     * @param data
     * @param <T>
     * @return
     */
    public static<T> List<T> getRepeat(List<T> data){
        List<T> list = new ArrayList<>();

        Iterator<T> iterator1 = data.iterator();
        while(iterator1.hasNext()) {
            T item1 = iterator1.next();
            Iterator<T> iterator2 = data.iterator();
            while (iterator2.hasNext()) {
                T item2 = iterator2.next();
                if(item1.equals(item2)){
                    iterator2.remove();
                    list.add(item2);
                    break;
                }
            }
        }

        return list;
    }

    /**
     * 判断Collection对象与Map对象是否为空
     * @param collection
     * @return
     */
    public static boolean isEmpty(Collection<?> collection) {
        return (collection == null || collection.isEmpty());
    }
    public static boolean isNotEmpty(Collection<?> collection) {
        return (collection != null && !collection.isEmpty());
    }
    public static<K,V> boolean isEmpty(Map<K,V> map){
        return map == null || map.size() == 0;
    }
    public static<K,V> boolean isNotEmpty(Map<K,V> map){
        return map != null && map.size() > 0;
    }
    public static boolean isEmpty(Object[] collection) {
        return (collection == null || collection.length == 0);
    }
    public static boolean isNotEmpty(Object[] collection) {
        return (collection != null && collection.length > 0);
    }


    /**
     * 如果Map的key对应的value为空，则根据类型
     * @param map
     * @param key
     * @param clazz
     */
    public static<K,V,Y,W> void isCreateMap(Map<K,V> map, K key, Class<V> clazz){
        V obj = map.get(key);
        if(obj == null){
            if(clazz.equals(List.class)){
                map.put(key, (V) new ArrayList<Y>());
            }else if(clazz.equals(Set.class)){
                map.put(key, (V) new HashSet<Y>());
            }else if(clazz.equals(Map.class)){
                map.put(key, (V) new HashMap<Y,W>(2));
            }else if(clazz.equals(ArrayList.class)){
                map.put(key, (V) new ArrayList<Y>());
            }else if(clazz.equals(LinkedHashSet.class)){
                map.put(key, (V) new LinkedHashSet<Y>());
            }else if(clazz.equals(TreeSet.class)){
                map.put(key, (V) new TreeSet<Y>());
            }else if(clazz.equals(TreeMap.class)){
                map.put(key, (V) new TreeMap<Y,W>());
            }else if(clazz.equals(LinkedHashMap.class)){
                map.put(key, (V) new LinkedHashMap<Y,W>());
            }
        }

    }

    public static<T> List<T> isCreateList(List<T> collection){
        if(collection == null) {
            collection = new ArrayList<>();
        }
        return collection;
    }

    public static<T> Set<T> isCreateSet(Set<T> collection){
        if(collection == null) {
            collection = new HashSet<>();
        }
        return collection;
    }

    /**
     * 判断集合/数组中是否存在某个元素
     * @param objs
     * @param obj
     * @return
     */
    public static<T> boolean isExist(T[] objs, T obj, Class<T> clazz, String... pros){
        List<T> objList = new ArrayList<> ();
        objList.addAll(Arrays.asList(objs));

        if(isEmpty(pros)){
            return objList.contains(obj);
        }else{
            for (String proStr : pros) {
                T pro = ReflectUtil.invokeMethod(obj, proStr);
                List<T> proList = getPros(objList, clazz, proStr);
                if(proList.contains(pro)){
                    return true;
                }
            }
        }
        return false;
    }


}
